home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Source Code / Think Class Libraries / CCicnButton 1.0 / CCicnButton.cp < prev    next >
Encoding:
Text File  |  1994-11-30  |  19.8 KB  |  809 lines  |  [TEXT/KAHL]

  1. /******************************************************************************
  2.  CCicnButton.cp
  3.  
  4.         An icon pane that acts like a button. It can have
  5.         push button, checkbox or radio button personalities.
  6.                 
  7.     SUPERCLASS = CIconPane
  8.     
  9.     Copyright © 1993 Martin R. Wachter. All rights reserved.
  10.     Portions Copyright © 1993 Object Factory Incorporated. All rights reserved.
  11.  
  12.     Original Author:     Martin R. Wachter        email:    mrw@welchgate.welch.jhu.edu
  13.     
  14.     Created:            12/4/93                    by:        mrw            TCL Version:    1.1.3
  15.  
  16.     Version change history:
  17.     
  18.     1.0        Initial release.
  19.  
  20.     Modified     12/4/93 by Martin R. Wachter (mrw)
  21.     
  22.                 Changed the way the icon is drawn by initializing the frame and
  23.                 aperature in ICicnButtonX() to that of the iconBMap.bounds rect.
  24.                                 
  25.                 Added itsLabels STR32s and itsColors RGBColors to dsplay a text label
  26.                 centered inside the cicn using draw string.  You can set
  27.                 the RGBColor of the text for each of the 4 states using 
  28.                 SetLabelColors().
  29.                 
  30.                 Added SetEnable() and SetDisable() methods to tell CPane
  31.                 to draw us grayed out if we are inactive and can not accept
  32.                 clicks.
  33.                 
  34.                 Added AdjustCursor Method to display a pointing finger cursor
  35.                 if we are active and enabled.  Added itsPointerHand data member
  36.                 to hold a CursHandle to the cursor.
  37.                 
  38.                 Moved ResetIconGroup() into this class so that it is not dependent
  39.                 upon CSwissArmyButton().
  40.  
  41.     0.1        Initial release by Bob Foster (ObjectFactory - CIconButton)
  42.                 
  43. ******************************************************************************/
  44.  
  45. #include "CCicnButton.h"
  46.  
  47. #include <OSChecks.h>
  48. #include <Commands.h>
  49. #include <Global.h>
  50. #include <OSChecks.h>
  51. #include <CPaneBorder.h>
  52. #include <CControl.h>
  53. #include <CList.h>
  54. #include <CWindow.h>
  55. #include <CEditText.h>
  56. #include <CColorTextEnvirons.h>
  57.  
  58. extern RgnHandle    gUtilRgn;        /* Utility region                    */
  59. extern RGBColor        gRGBBlack;        /* Black color for everyone to use    */
  60. extern RGBColor        gRGBWhite;        /* White color for everyone to use    */
  61.  
  62. /*
  63.  *    TCL 1.1.2 DLP 12/10/91
  64.  *    When available, we now use the System 7 Icon Utilities for drawing cicns
  65.  *  See TN #306 for more information
  66.  */
  67.  
  68. #define tcl_IconDispatch    0xABC9
  69.  
  70. #define kPointerHandCursor 1024
  71.  
  72. pascal OSErr tcl_PlotCIconHandle( Rect*, short, short, CIconHandle) = { 0x303C, 0x61F, tcl_IconDispatch};
  73.  
  74. /******************************************************************************
  75.  ICicnButton
  76.  
  77.      Initialize an CicnButton. The button may use up to four CICN (ICON)
  78.      icons, to represent the off, off/hilite, on, on/hilite states.
  79.      If hiliting is done by dimming and/or if the on state is indicated
  80.      by a border, the IDs for the unused states should be set the same
  81.      as the iconID. Other states can be duplicated, as well. For example,
  82.      the hilite states may be graphically the same for both on and off.
  83. ******************************************************************************/
  84.  
  85. void CCicnButton::ICicnButton(CView *anEnclosure, CBureaucrat *aSupervisor,
  86.                     short aHEncl, short aVEncl,
  87.                     SizingOption aHSizing, SizingOption aVSizing,
  88.                     short aButtonKind, short hilightStyle, short onStyle,
  89.                     short offID, short offHiliteID, short onID, short onHiliteID)
  90. {
  91.     short        i;
  92.     Rect        r;
  93.     
  94.     CIconPane::IIconPane(anEnclosure, aSupervisor,
  95.                     aHEncl, aVEncl,
  96.                     aHSizing, aVSizing,
  97.                     offID, TRUE);
  98.  
  99.     wantsClicks = TRUE;
  100.  
  101.     buttonKind = aButtonKind;
  102.     colorHilite = hilightStyle;
  103.     outlineOn = onStyle;
  104.     value = 0;
  105.     SetGroupID(0);
  106.     if (outlineOn)
  107.         FixupBorder();
  108.  
  109.     ICicnButtonX(offHiliteID, onID, onHiliteID);
  110.  
  111. }
  112.  
  113.  
  114. /******************************************************************************
  115.  ICicnButtonX
  116.  
  117.      Fill in the icon arrays
  118. ******************************************************************************/
  119.  
  120. void CCicnButton::ICicnButtonX(short offHiliteID, short onID, short onHiliteID)
  121. {
  122. short    i;
  123.  
  124.         // Copy the first icon to array
  125.  
  126.     itsIconID[0] = iconID;
  127.     BlockMove(&icon, &itsIcon[0], kIconBytes);
  128.     itsCicnH[0] = cicnH;
  129.     
  130.     // size the frame to that of the cicn's size        added 12/93 mrw
  131.     width = height = 0;
  132.     ResizeFrame(&((**cicnH).iconPMap).bounds);
  133.     CalcAperture();
  134.     
  135.         // Now do the rest
  136.  
  137.     SetStateIcons(offHiliteID, onID, onHiliteID);
  138.  
  139.     itsPointerHand = GetCursor(kPointerHandCursor);
  140.     HNoPurge( (Handle) itsPointerHand);
  141.     
  142.     // initialize itsLabels to empty strings
  143.     for (i=0;i<4;i++){
  144.         CopyPString("\p",itsLabels[i]);
  145.     }
  146.     
  147.     
  148.     // initialize label colors to black and white
  149.     SetLabelColors(gRGBWhite,gRGBBlack,gRGBWhite,gRGBBlack);
  150.     
  151.     // initialize itsShadow to draw NO shadow
  152.     itsShadow = 0;
  153. }
  154.  
  155.  
  156. /******************************************************************************
  157.  Dispose    {OVERRIDE}
  158.  
  159.      Free the color icon if it exists
  160. ******************************************************************************/
  161.  
  162. void  CCicnButton::Dispose(void)
  163. {
  164.     short        i, j;
  165.  
  166.         // Dispose all the CICN handles here, making sure not
  167.         // to dispose duplicated items twice.
  168.  
  169.     for (i = 0; i < 4; i++)
  170.     {
  171.         for (j = 0; j < i; j++)
  172.             if (itsCicnH[i] == itsCicnH[j])
  173.                 break;
  174.         if (j == i && itsCicnH[i])
  175.             DisposCIcon(itsCicnH[i]);
  176.     }
  177.  
  178.         // Keep CIconPane from trying to dispose again
  179.  
  180.     cicnH = NULL;
  181.  
  182.     CIconPane::Dispose();
  183. }
  184.  
  185.  
  186. /******************************************************************************
  187.  SetStateIcons
  188.  
  189.      Add the icons used by the various states. The icon
  190.      specified in initialization is taken to be the icon for the
  191.      off, non-hilite state. If a state has no corresponding icon,
  192.      the ID of a previous state should be specified.
  193. ******************************************************************************/
  194.  
  195. void CCicnButton::SetStateIcons(short offHiliteID, short onID, short onHiliteID)
  196. {
  197.     short        i, j;
  198.  
  199.     itsIconID[1] = offHiliteID;
  200.     itsIconID[2] = onID;
  201.     itsIconID[3] = onHiliteID;
  202.  
  203.     for (i = 1; i < 4; i++)
  204.     {
  205.         for (j = 0; j < i; j++)
  206.             if (itsIconID[j] == itsIconID[i])
  207.                 break;
  208.         if (j != i)                        // If duplicate icon ID
  209.         {
  210.                 // Same as previous ID, so just copy the info
  211.  
  212.             BlockMove(&itsIcon[j], &itsIcon[i], kIconBytes);
  213.             itsCicnH[i] = itsCicnH[j];
  214.         }
  215.         else
  216.         {
  217.                 // If not the same as a previous icon ID, let
  218.                 // initialization method read the resource
  219.  
  220.             iconID = itsIconID[i];
  221.             CIconPane::IIconPaneX(TRUE);
  222.             BlockMove(&icon, &itsIcon[i], kIconBytes);
  223.             itsCicnH[i] = cicnH;
  224.         }
  225.     }
  226.     iconID = itsIconID[0];                // Restore this in case anyone looks
  227. }
  228.  
  229. /******************************************************************************
  230.  SetLabelColors
  231.  
  232.      Set the RGB colors of the labels.
  233.  
  234. ******************************************************************************/
  235.  
  236. void CCicnButton::SetLabelColors(RGBColor offColor, RGBColor offHiliteColor, 
  237.                                  RGBColor onColor, RGBColor onHiliteColor)
  238.  
  239. {
  240.     itsColors[kSAOffState] = offColor;
  241.     itsColors[kSAOffHiliteState] = offHiliteColor;
  242.     itsColors[kSAOnState] = onColor;
  243.     itsColors[kSAOnHiliteState] = onHiliteColor;
  244.  
  245. }
  246. /******************************************************************************
  247.  SetLabel
  248.  
  249.      Initializes itsLabels to use strings from an STR# resource.
  250.      aShadow is used to to set itsShadow, for drawing a drop shadow
  251.      behing the label.
  252.      
  253. ******************************************************************************/
  254.  
  255. void CCicnButton::SetLabel(short strListID, 
  256.                             short offIndex, short offHiliteIndex, short onIndex, short onHiliteIndex,
  257.                             short fontNumber, short fontFace, short fontSize, short aShadow)
  258. {
  259.     Str255        theString;
  260.     short        i;
  261.     TextInfoRec    textInfo;
  262.     CColorTextEnvirons        *itsTextEnv;
  263.     
  264.     itsTextEnv = new CColorTextEnvirons;
  265.     itsTextEnv->IColorTextEnvirons();
  266.     textInfo.fontNumber = fontNumber;
  267.     textInfo.theSize = fontSize;
  268.     textInfo.theStyle = fontFace;
  269.     textInfo.theMode = 0;
  270.     
  271.     itsTextEnv->SetTextInfo(&textInfo);
  272.     
  273.     itsEnvironment = itsTextEnv;
  274.  
  275.     GetIndString(theString,strListID,offIndex);
  276.     CopyPString(theString,itsLabels[0]);
  277.     GetIndString(theString,strListID,offHiliteIndex);    
  278.     CopyPString(theString,itsLabels[1]);
  279.     GetIndString(theString,strListID,onIndex);    
  280.     CopyPString(theString,itsLabels[2]);
  281.     GetIndString(theString,strListID,onHiliteIndex);
  282.     CopyPString(theString,itsLabels[3]);
  283.         
  284.     itsShadow = aShadow;
  285. }
  286.  
  287. /******************************************************************************
  288.  SetShadow
  289.  
  290.      Sets the itsShadow data member for drawing a drop shadow behind itsLabels.
  291.      
  292. ******************************************************************************/
  293.  
  294. void CCicnButton::SetShadow(short aShadow)
  295. {
  296.     itsShadow = aShadow;
  297. }
  298.  
  299. /******************************************************************************
  300.  GetShadow
  301.  
  302.      Returns the current value of the itsShadow data member.
  303.      
  304. ******************************************************************************/
  305.  
  306. short CCicnButton::GetShadow(short aShadow)
  307. {
  308.     return itsShadow;
  309. }
  310.  
  311. /******************************************************************************
  312.  CalcDrawState
  313.  
  314.      Draw the icon normally or hilited. The CIconPane method does most
  315.      of the drawing.
  316. ******************************************************************************/
  317.  
  318. short CCicnButton::CalcDrawState(Boolean fHilite)
  319. {
  320.     return value * (outlineOn ? 0 : 2) + (colorHilite ? 0 : fHilite);
  321. }
  322.  
  323. /******************************************************************************
  324.  SetEnable
  325.  
  326.      Enable an CicnButton.  Sets the icon to accept clicks.
  327.      
  328. ******************************************************************************/
  329.  
  330. void CCicnButton::SetEnable()
  331. {
  332.     if (!enabled){
  333.         enabled = TRUE;
  334.         SetWantsClicks(TRUE);
  335.         Refresh();
  336.     }
  337. }
  338.  
  339. /******************************************************************************
  340.  SetDisable
  341.  
  342.      Disables an CicnButton.  Sets the icon to not accept clicks and to be
  343.      drawn in gray.
  344.      
  345. ******************************************************************************/
  346.  
  347. void CCicnButton::SetDisable()
  348. {
  349.     if (enabled){
  350.         enabled = FALSE;
  351.         SetWantsClicks(FALSE);
  352.         Refresh();
  353.     }
  354. }
  355.  
  356. /******************************************************************************
  357.  GetEnable
  358.  
  359.      Returns the current enable data member for an icon button.
  360.      
  361. ******************************************************************************/
  362.  
  363. short CCicnButton::GetEnable()
  364. {
  365.     return enabled;
  366. }
  367.  
  368.  
  369. /******************************************************************************
  370.  DrawIcon
  371.  
  372.      Draw the icon normally or hilited. The CIconPane method does most
  373.      of the drawing.
  374. ******************************************************************************/
  375.  
  376. void CCicnButton::DrawIcon(Boolean fHilite)
  377. {
  378.     short    drawState = CalcDrawState(fHilite);
  379.  
  380.     Rect        tempRect,theBounds = { 0, 0, kIconPixels, kIconPixels};
  381.     short        copyMode = fHilite ? srcOr : srcBic;
  382.     RGBColor    fore, back;
  383.     
  384.     
  385.         // Set up the correct icon
  386.  
  387.     cicnH = itsCicnH[drawState];
  388.     BlockMove(&itsIcon[drawState], &icon, kIconBytes);
  389.     Prepare();
  390.  
  391.     if (gSystem.hasColorQD)    // preserve foreground and background colors
  392.     {
  393.         GetForeColor( &fore);
  394.         GetBackColor( &back);
  395.     }
  396.     ForeColor( blackColor);    // set default colors for CopyBits
  397.     BackColor( whiteColor);    
  398.         
  399.     if (cicnH)
  400.     {
  401.         theBounds = ((**cicnH).iconBMap).bounds;
  402.  
  403.         // To draw the cicn highlighted, we make a copy of the cicn's
  404.         // pixmap color table and "dim" it by modifying the RGB values.    
  405.         if (fHilite && colorHilite)
  406.         {
  407.             CTabHandle    ctab = (**cicnH).iconPMap.pmTable, dupCTable;
  408.             short        i, numColors;
  409.             ColorSpec    *cspec;
  410.  
  411.             dupCTable = ctab;
  412.             
  413.                 // let this memory allocation come from the reserve if necessary.
  414.                 // we'll be giving it back almost immediately.
  415.             HandToHand((Handle *) &dupCTable);
  416.             
  417.             numColors = (**ctab).ctSize; // number of colors in cicn's color table
  418.             cspec = (**ctab).ctTable;    // point to first ColorSpec in the color table
  419.             for(i = 0; i < numColors; i++)
  420.             {
  421.                 cspec->rgb.red /= 2;    // dim by halving the RGBs
  422.                 cspec->rgb.green /= 2;
  423.                 cspec->rgb.blue /= 2;
  424.                 ++cspec;
  425.             }
  426.             PlotCIcon( &theBounds, cicnH); // plot it dimmed
  427.             
  428.                 // put back the undimmed color table, then free the dimmed one.
  429.             (**cicnH).iconPMap.pmTable = dupCTable;
  430.             DisposCTable( ctab);
  431.         }
  432.         else{    // no dimming, just plot it normally
  433.             
  434.             PlotCIcon( &theBounds, cicnH);
  435.             DrawLabel( &theBounds,drawState);
  436.         }
  437.     }
  438.     else    // draw the b&w icon
  439.     {
  440.         BitMap  theImage;
  441.         Boolean wasLocked = Lock( TRUE);
  442.         theImage.baseAddr = icon;
  443.         theImage.rowBytes = kIconRowBytes;
  444.         
  445.         theImage.bounds = theBounds;
  446.                 
  447.         CalcMask( icon, cIconMaskBits, kIconRowBytes, kIconRowBytes, kIconPixels, 2);
  448.  
  449.         CopyBits( &cMaskBitMap, &thePort->portBits, &theBounds, &theBounds, copyMode, NULL);
  450.         CopyBits( &theImage, &thePort->portBits, &theBounds, &theBounds, srcXor, NULL); 
  451.      
  452.         Lock( wasLocked);    
  453.     }
  454.     if (gSystem.hasColorQD)    // restore the colors
  455.     {
  456.         RGBForeColor( &fore);
  457.         RGBBackColor( &back);
  458.     }
  459.  
  460. }
  461.  
  462. /******************************************************************************
  463.  DrawLabel
  464.  
  465.      Draw the text label for the button and optionaly draw itsShadow.
  466.      
  467. ******************************************************************************/
  468.  
  469. void CCicnButton::DrawLabel(Rect *fBounds, short state)
  470. {
  471.     Str32        label;
  472.     short        iWidth;
  473.     FontInfo    fInfo;
  474.     
  475.     CopyPString(itsLabels[state], label);
  476.  
  477.     iWidth = StringWidth(label);
  478.     GetFontInfo(&fInfo);
  479.     
  480.     TextMode(srcOr);
  481.     
  482.     if (itsShadow){
  483.  
  484.         // draw the background shaddow
  485.         switch(state){
  486.             case kSAOffState:
  487.             case kSAOnState:
  488.                 RGBForeColor( &gRGBBlack);
  489.                 break;
  490.             
  491.             case kSAOffHiliteState:
  492.             case kSAOnHiliteState:
  493.                 RGBForeColor( &gRGBWhite);
  494.                 break;
  495.         }
  496.     
  497.         MoveTo((((*fBounds).right - iWidth)/2)+itsShadow,(((*fBounds).bottom/2 + fInfo.ascent/2) - fInfo.descent)+itsShadow);
  498.         DrawString(label);
  499.     }
  500.     
  501.     // draw the text on top of the label
  502.     RGBForeColor( &itsColors[state]);
  503.     MoveTo(((*fBounds).right - iWidth)/2,((*fBounds).bottom/2 + fInfo.ascent/2) - fInfo.descent);
  504.     DrawString(label);
  505.         
  506.  
  507. }
  508.  
  509. /******************************************************************************
  510.  ChangeValue
  511.  
  512.      Change the value for an CicnButton. Like SetValue, with no
  513.      Refresh.
  514. ******************************************************************************/
  515.  
  516. void CCicnButton::ChangeValue(short aValue)
  517. {
  518.     if (aValue != value)
  519.     {
  520.         if (aValue)                        // Interact with the group as approp.
  521.             ResetIconGroup();
  522.  
  523.         value = aValue;                    // OK to change value now
  524.  
  525.                                         // Tell dependents, just like any
  526.                                         //     other control
  527.         BroadcastChange(controlValueChanged, &aValue);
  528.  
  529.         FixupBorder();                    // Border changes based on value
  530.     }
  531. }
  532.  
  533.  
  534. /******************************************************************************
  535.  SetValue
  536.  
  537.      Set the value for an CicnButton
  538. ******************************************************************************/
  539.  
  540. void CCicnButton::SetValue(short aValue)
  541. {
  542.     if (buttonKind == kSAPushButton)    // Can't change value of pushbutton
  543.         return;
  544.  
  545.     aValue = aValue & 1;                // Only values 0 and 1 are allowed
  546.  
  547.     if (aValue != value)
  548.     {
  549.         ChangeValue(aValue);
  550.         if (!outlineOn)
  551.             Refresh();
  552.     }
  553. }
  554.  
  555.  
  556. /******************************************************************************
  557.  GetValue
  558.  
  559.      Get the value for an CicnButton
  560. ******************************************************************************/
  561.  
  562. short CCicnButton::GetValue()
  563. {
  564.     return value;
  565. }
  566.  
  567.  
  568. /******************************************************************************
  569.  SetGroupID
  570.  
  571.      Set the group ID
  572. ******************************************************************************/
  573.  
  574. void CCicnButton::SetGroupID(short anID)
  575. {
  576.     groupID = anID;
  577. }
  578.  
  579.  
  580. /******************************************************************************
  581.  GetGroupID
  582.  
  583.      Get the group ID
  584. ******************************************************************************/
  585.  
  586. short CCicnButton::GetGroupID()
  587. {
  588.     return groupID;
  589. }
  590.  
  591.  
  592. /******************************************************************************
  593.  SetButtonKind
  594.  
  595.      Set the button action
  596. ******************************************************************************/
  597.  
  598. void CCicnButton::SetButtonKind(short aKind)
  599. {
  600.     buttonKind = aKind;
  601. }
  602.  
  603.  
  604. /******************************************************************************
  605.  GetButtonKind
  606.  
  607.      Get the button action
  608. ******************************************************************************/
  609.  
  610. short CCicnButton::GetButtonKind()
  611. {
  612.     return buttonKind;
  613. }
  614.  
  615.  
  616. /******************************************************************************
  617.  DoDrawIcon
  618.  
  619.      Check whether icon needs to be erased before redrawing.
  620.      B&W icons do, color icons don't.
  621. ******************************************************************************/
  622.  
  623. void CCicnButton::DoDrawIcon(Boolean fHilite)
  624. {
  625.     Rect    erase;
  626.  
  627.     if (itsCicnH[CalcDrawState(fHilite)] == NULL)
  628.     {
  629.         FrameToQDR(&frame, &erase);
  630.         EraseRect(&erase);
  631.     }
  632.     DrawIcon(fHilite);
  633. }
  634.  
  635.  
  636. /******************************************************************************
  637.  AdjustCursor {OVERRIDE}
  638.  
  639.         Mouse is inside a CCicnButton Pane. Use the pointing finger cursor.
  640.  ******************************************************************************/
  641.  
  642. void    CCicnButton::AdjustCursor(
  643.     Point        where,                    /* Mouse location in Window coords    */
  644.     RgnHandle    mouseRgn)
  645. {
  646.     if (GetEnable())
  647.         SetCursor(*itsPointerHand);
  648. }
  649.  
  650.  
  651. /******************************************************************************
  652.  Track    {OVERRIDE}
  653.  
  654.      Override Track to set the value if the mouse winds up in the icon.
  655.      Also, Track called DrawIcon one too many times, resulting in an
  656.      unnecessary flash for a button with multiple states.
  657. ******************************************************************************/
  658.  
  659. Boolean CCicnButton::Track(void)
  660. {
  661.     short        oldValue = value;
  662.     Boolean        wasInButton = TRUE;
  663.     Point        where;
  664.     Rect        iconFrame;
  665.  
  666.     LongToQDRect(&frame, &iconFrame);
  667.  
  668.     DoDrawIcon(TRUE);
  669.     
  670.     while (StillDown())
  671.     {
  672.         GetMouse(&where);
  673.         if (PtInRect(where, &iconFrame))
  674.         {
  675.             if (!wasInButton)
  676.                 DoDrawIcon(TRUE);
  677.             wasInButton = TRUE;
  678.         }
  679.         else
  680.         {
  681.             if (wasInButton)
  682.                 DoDrawIcon(FALSE);
  683.             wasInButton = FALSE;
  684.         }
  685.     }
  686.  
  687.     if (wasInButton && buttonKind > kSAPushButton)
  688.     {
  689.         if (buttonKind == kSACheckBox)
  690.             ChangeValue(1 - value);
  691.             
  692.         else if (buttonKind == kSARadioButton){
  693.             ResetIconGroup();
  694.             ChangeValue(1);
  695.         }
  696.         else
  697.             ChangeValue(1);
  698.     }
  699.  
  700.         // Now it's OK to redraw the button, after it has
  701.         // been set to its final state
  702.  
  703.     DoDrawIcon(FALSE);
  704.  
  705.     return wasInButton;
  706. }
  707.  
  708.  
  709. /******************************************************************************
  710.  FixupBorder
  711.  
  712.      Fixup the border per the current button state
  713. ******************************************************************************/
  714.  
  715. void CCicnButton::FixupBorder()
  716. {
  717.     Point    pensize;
  718.     Rect    wFrame;
  719.  
  720.     if (outlineOn && itsBorder == NULL)
  721.     {
  722.         Rect        margin;
  723.         CPaneBorder    *border;
  724.  
  725.         border = new CPaneBorder;
  726.         border->IPaneBorder(kBorderFrame);
  727.         SetRect(&margin, -1, -1, 1, 1);
  728.         border->SetMargin(&margin);
  729.         border->SetPenSize(2, 2);
  730.         SetBorder(border);
  731.     }
  732.     if (value == 0 && itsBorder)
  733.     {
  734.         itsBorder->GetPenSize(&pensize.h, &pensize.v);
  735.         if (pensize.h)
  736.         {
  737.             RefreshBorder();
  738.             FrameToWindR(&frame, &wFrame);
  739.             ValidRect(&wFrame);
  740.             itsBorder->SetPenSize(0, 0);
  741.             borderPen = pensize;
  742.         }
  743.     }
  744.     else if (value && outlineOn)
  745.     {
  746.         Point    pensize;
  747.  
  748.         itsBorder->GetPenSize(&pensize.h, &pensize.v);
  749.         if (pensize.h == 0)
  750.         {
  751.             itsBorder->SetPenSize(borderPen.h, borderPen.v);
  752.             RefreshBorder();
  753.             FrameToWindR(&frame, &wFrame);
  754.             ValidRect(&wFrame);
  755.         }
  756.     }
  757. }
  758.  
  759. /******************************************************************************
  760.   ResetIconGroup
  761.  
  762.     Reset a button group according to kind of button
  763. ******************************************************************************/
  764.     typedef struct {
  765.         CCicnButton    *pane;
  766.         short    group;
  767.         Boolean    radio;
  768.     } ResetRec;
  769.  
  770.     static void ResetButtons(CCicnButton *pane, ResetRec *rec)
  771.     {
  772.         short    group, kind;
  773.         
  774.             // Don't reset self
  775.  
  776.         if (pane == rec->pane)
  777.             return;
  778.  
  779.             if (member( pane, CCicnButton) && rec->radio && (rec->group == pane->groupID)){
  780.                 pane->ChangeValue(0);
  781.                 pane->DoDrawIcon(0);
  782.             }
  783.  
  784.     }
  785.  
  786. void CCicnButton::ResetIconGroup(void)
  787. {
  788.     ResetRec    rec;
  789.     
  790.     rec.group = groupID;
  791.  
  792.     if (rec.group == 0 || buttonKind == 0)
  793.         return;
  794.     
  795.     rec.pane = this;
  796.  
  797.     switch (buttonKind)
  798.     {
  799.         case kSARadioButton:
  800.             rec.radio = TRUE;
  801.             break;
  802.         case kSACheckBox:
  803.             rec.radio = FALSE;
  804.             break;
  805.     }
  806.     
  807.     itsEnclosure->itsSubviews->DoForEach1((EachFunc1) ResetButtons, (long) &rec);
  808. }
  809.